#import "SSJailbreakCheck.h"
#import <UIKit/UIKit.h>
#import <sys/stat.h>
#import <sys/sysctl.h>
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
enum {
    KFJailbroken = 3429542,
    KFOpenURL = 321,
    KFCydia = 432,
    KFIFC = 47293,
    KFPlist = 9412,
    KFSymbolic = 34859,
    KFFileExists = 6625,
} JailbrokenChecks;
@implementation SSJailbreakCheck
+ (int)jailbroken {
    int motzart = 0;
    if (SYSTEM_VERSION_LESS_THAN(@"9.0")) {
        if ([self urlCheck] != NOTJAIL) {
            motzart += 3;
        }
    }
    if ([self cydiaCheck] != NOTJAIL) {
        motzart += 3;
    }
    if ([self inaccessibleFilesCheck] != NOTJAIL) {
        motzart += 2;
    }
    if ([self plistCheck] != NOTJAIL) {
        motzart += 2;
    }
    if ([self symbolicLinkCheck] != NOTJAIL) {
        motzart += 2;
    }
    if ([self filesExistCheck] != NOTJAIL) {
        motzart += 2;
    }
    if (motzart >= 3) {
        return KFJailbroken;
    }
    return NOTJAIL;
}
#pragma mark - Static Jailbreak Checks
+ (int)urlCheck {
    @try {
        #if !(defined(__has_feature) && __has_feature(attribute_availability_app_extension))
            NSURL *fakeURL = [NSURL URLWithString:CYDIAPACKAGE];
            if ([[UIApplication sharedApplication] canOpenURL:fakeURL])
               return KFOpenURL;
        #endif
    }
    @catch (NSException *exception) {
        return NOTJAIL;
    }
    return NOTJAIL;
}
+ (int)cydiaCheck {
    @try {
        NSString *filePath = CYDIALOC;
        if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
            return KFCydia;
        } else {
            return NOTJAIL;
        }
    }
    @catch (NSException *exception) {
        return NOTJAIL;
    }
}
+ (int)inaccessibleFilesCheck {
    @try {
        for (NSString *key in HIDDENFILES) {
            if ([[NSFileManager defaultManager] fileExistsAtPath:key]) {
                return KFIFC;
            }
        }
        return NOTJAIL;
    }
    @catch (NSException *exception) {
        return NOTJAIL;
    }
}
+ (int)plistCheck {
    @try {
        NSString *exeName = EXEPATH;
        NSDictionary *ipl = PLISTPATH;
        if ([FILECHECK exeName] == FALSE || ipl == nil || ipl.count <= 0) {
            return KFPlist;
        } else {
            return NOTJAIL;
        }
    }
    @catch (NSException *exception) {
        return NOTJAIL;
    }
}
+ (int)symbolicLinkCheck {
    @try {
        struct stat s;
        if (lstat("/Applications", &s) != 0) {
            if (s.st_mode & S_IFLNK) {
                return KFSymbolic;
            } else
                return NOTJAIL;
        } else {
            return NOTJAIL;
        }
    }
    @catch (NSException *exception) {
        return NOTJAIL;
    }
}
+ (int)filesExistCheck {
    @try {
        if (![FILECHECK [[NSBundle mainBundle] executablePath]]) {
            return KFFileExists;
        } else
            return NOTJAIL;
    }
    @catch (NSException *exception) {
        return NOTJAIL;
    }
}
+ (NSArray *)runningProcesses {
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
    size_t miblen = 4;
    size_t size = 0;
    int st;
    struct kinfo_proc * process = NULL;
    struct kinfo_proc * newprocess = NULL;
    do {
        size += (size / 10);
        newprocess = realloc(process, size);
        if (!newprocess){
            if (process){
                free(process);
            }
            return nil;
        }
        process = newprocess;
        st = sysctl(mib, (int)miblen, process, &size, NULL, 0);
    } while (st == -1 && errno == ENOMEM);
    if (st == 0){
        if (size % sizeof(struct kinfo_proc) == 0){
            int nprocess = (int)(size / sizeof(struct kinfo_proc));
            if (nprocess){
                NSMutableArray * array = [[NSMutableArray alloc] init];
                for (int i = nprocess - 1; i >= 0; i--){
                    NSString * processID = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_pid];
                    NSString * processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm];
                    NSString *processPriority = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_priority];
                    NSDate   *processStartDate = [NSDate dateWithTimeIntervalSince1970:process[i].kp_proc.p_un.__p_starttime.tv_sec];
                    NSDictionary *dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processPriority, processName, processStartDate, nil]
                                                                       forKeys:[NSArray arrayWithObjects:@"ProcessID", @"ProcessPriority", @"ProcessName", @"ProcessStartDate", nil]];
                    [array addObject:dict];
                }
                free(process);
                return array;
            }
        }
    }
    free(process);
    return nil;
}
@end
